// std::declval 详解
// std::declval是C++11引入的一个模板函数，主要用于类型推导和模板元编程。
// 它解决了一个关键问题：如何在不实际创建对象的情况下，获取对象的类型信息。

// 1. 基本定义
template <class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
// 简化理解：它"假装"返回一个T类型的右值引用，但实际上它没有定义（只有声明）。

// 2. 主要用途
// 2.1 在decltype中使用
// 获取函数返回类型，而不需要构造对象
template <typename T>
using result_type = decltype(std::declval<T>().someMethod(5));

// 2.2 类型特性检测
// 检测类是否有特定方法
template <typename T, typename = void>
struct has_toString : std::false_type
{
};

// 偏特化
template <typename T>
struct has_toString<T, std::void_t<decltype(std::declval<T>().toString())>>
    : std::true_type
{
};

// 3. 为什么需要declval
// 3.1 解决的问题
//  1.避免构造对象：
//      不需要类型T有默认构造函数
//      不需要实际创建对象实例
//  2.处理不可构造的类型：
//      抽象类
//      没有默认构造函数的类
//      不完整类型

// 工作原理
// 1.仅用于编译时：
// declval只在未求值上下文中使用（如decltype内部）
// 它没有函数体，不能在运行时调用
// 2.返回右值引用：
// 返回T&&使得可以调用任何成员函数，包括右值引用限定的函数

// 5. 实际示例
// 5.1 获取复杂表达式的返回类型
template <typename T, typename U>
auto add(T t, U u) -> decltype(std::declval<T>() + std::declval<U>())
{
    return t + u;
}

// 5.2 完美转发构造函数
template <typename T, typename... Args>
using can_construct = std::is_constructible<T, Args...>;

template <typename T, typename... Args>
std::enable_if_t<can_construct<T, Args...>::value, std::unique_ptr<T>>
make_unique(Args &&...args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// 6. 注意事项
//  1.仅用于未求值上下文：
//      只能在decltype、sizeof、noexcept等内部使用
//      不能在运行时代码中使用
//  2.不要尝试调用它：
auto x = std::declval<int>(); // 编译错误！
//  3.与其他类型特性配合使用：
// 通常与decltype、std::void_t等一起使用
